using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class IptPrcs
{
    private int _iptNum;
    private Image[] _iptImgs;
    /// <summary>
    /// 0: num; 1: word; 2: num; 3: word; 4: word
    /// </summary>
    private Image[] _wordImgs;
    private Queue<IptType> _iptQue;

    private Sprite _emptyIpt;
    private Sprite[] _words;
    private Sprite[] _pWords;
    private Sprite[] _wordNums;

    public IptPrcs(Image[] iptImgs, Image[] wordImgs, Sprite empty, Sprite[] words, Sprite[] pWords, Sprite[] wordNums)
    {
        _iptNum = iptImgs.Length;
        _iptImgs = iptImgs;
        _wordImgs = wordImgs;
        _iptQue = new Queue<IptType>();

        _emptyIpt = empty;
        _words = words;
        _pWords = pWords;
        _wordNums = wordNums;
        ClearIpt();
        ClearWords();

        _typeNumDic = new Dictionary<IptType, int>();
        _pNumDic = new Dictionary<IptType, int>();
        _iptKeyLs = new List<IptType>();
    }

    public void ClearIpt()
    {
        foreach (Image ipt in _iptImgs) ipt.sprite = _emptyIpt;
        _iptQue.Clear();
    }

    public void ClearWords()
    {
        foreach (Image word in _wordImgs) word.gameObject.SetActive(false);
    }

    public void Ipt(IptType it, Sprite iptSprite)
    {
        if (_iptQue.Count < _iptNum)
        {
            _iptImgs[_iptQue.Count].sprite = iptSprite;
            _iptQue.Enqueue(it);
        }
        else
        {
            _iptQue.Dequeue();
            _iptQue.Enqueue(it);
            for (int i = 0; i < _iptNum - 1; i++)
            {
                _iptImgs[i].sprite = _iptImgs[i + 1].sprite;
            }
            _iptImgs[_iptNum - 1].sprite = iptSprite;
        }
    }

    private Dictionary<IptType, int> _typeNumDic;
    /// <summary>
    /// Perfect num dic.
    /// </summary>
    private Dictionary<IptType, int> _pNumDic;
    private List<IptType> _iptKeyLs;

    public void GenWords()
    {
        if (_iptQue.Count == 0) return;
        _typeNumDic.Clear();
        _pNumDic.Clear();
        _iptKeyLs.Clear();
        ClearWords();

        #region Count ipt num
        foreach (IptType it in _iptQue)
        {
            switch (it)
            {
                case IptType.South:
                case IptType.West:
                case IptType.North:
                case IptType.East:
                    RegIpt(it);
                    break;
                case IptType.PSouth://analyse as normal version
                    RegIpt(IptType.South);
                    if (_pNumDic.ContainsKey(IptType.South)) _pNumDic[IptType.South]++;
                    else _pNumDic.Add(IptType.South, 1);
                    break;
                case IptType.PWest:
                    RegIpt(IptType.West);
                    if (_pNumDic.ContainsKey(IptType.West)) _pNumDic[IptType.West]++;
                    else _pNumDic.Add(IptType.West, 1);
                    break;
                case IptType.PNorth:
                    RegIpt(IptType.North);
                    if (_pNumDic.ContainsKey(IptType.North)) _pNumDic[IptType.North]++;
                    else _pNumDic.Add(IptType.North, 1);
                    break;
                case IptType.PEast:
                    RegIpt(IptType.East);
                    if (_pNumDic.ContainsKey(IptType.East)) _pNumDic[IptType.East]++;
                    else _pNumDic.Add(IptType.East, 1);
                    break;
                default:
                    break;
            }
        }
        #endregion
        #region Sort ls by num
        IptType tempType;
        for (int i = 0; i < _iptKeyLs.Count - 1; i++)
        {
            for (int j = _iptKeyLs.Count - 1; j > i; j--)
            {
                if (_typeNumDic[_iptKeyLs[j]] > _typeNumDic[_iptKeyLs[j - 1]])
                {
                    tempType = _iptKeyLs[j];
                    _iptKeyLs[j] = _iptKeyLs[j - 1];
                    _iptKeyLs[j - 1] = tempType;
                }
            }
        }
        #endregion
        #region Calligraphy
        if (_iptKeyLs.Count == 1)
        {
            DsplFullFormat(1, _iptKeyLs[0]);
            _wordImgs[3].gameObject.SetActive(true);
            _wordImgs[3].sprite = _wordNums[0];
            _wordImgs[3].gameObject.GetComponent<RectTransform>().rotation = Quaternion.AngleAxis(0, Vector3.forward);//rotate
        }
        else if (_iptKeyLs.Count == 2)
        {
            DsplFullFormat(1, _iptKeyLs[0]);
            DsplFullFormat(3, _iptKeyLs[1]);
        }
        else if (_iptKeyLs.Count == 3)
        {
            DsplFullFormat(1, _iptKeyLs[0]);
            if (_typeNumDic[_iptKeyLs[1]] > 1)//only {2, 2, 1}
            {
                DsplFullFormat(3, _iptKeyLs[1]);
                DsplWord(4, _iptKeyLs[2]);
            }
            else
            {
                DsplWord(2, _iptKeyLs[1]);
                DsplWord(3, _iptKeyLs[2]);
            }
        }
        else if (_iptKeyLs.Count == 4)
        {
            if (_typeNumDic[_iptKeyLs[0]] == 2)//at most 2
            {
                if (_pNumDic[_iptKeyLs[0]] == 2)//perfect 2
                {
                    _typeNumDic[_iptKeyLs[0]] = 1;
                    _pNumDic[_iptKeyLs[0]] = 1;//one perfect, img[0] display perfect
                    TheWholeFamily();
                    DsplWord(4, _iptKeyLs[0]);//img[4] display perfect
                }
                else if (_pNumDic[_iptKeyLs[0]] == 1)//normal and perfect
                {
                    _typeNumDic[_iptKeyLs[0]] = 1;
                    _pNumDic[_iptKeyLs[0]] = 1;//one perfect, img[0] display perfect
                    TheWholeFamily();
                    _pNumDic[_iptKeyLs[0]] = 0;
                    DsplWord(4, _iptKeyLs[0]);//img[4] display normal
                }
                else if (_pNumDic[_iptKeyLs[0]] == 0)//all normal
                {
                    _typeNumDic[_iptKeyLs[0]] = 1;//one normal, img[4] display normal
                    TheWholeFamily();
                    DsplWord(4, _iptKeyLs[0]);//img[4] display normal
                }
            }
            else TheWholeFamily();//{1, 1, 1, 1}
        }
        #endregion
        ClearIpt();
    }

    private void TheWholeFamily()
    {
        DsplWord(0, IptType.South);
        DsplWord(1, IptType.East);
        DsplWord(2, IptType.West);
        DsplWord(3, IptType.North);
    }

    private void RegIpt(IptType it)
    {
        if (!_pNumDic.ContainsKey(it)) _pNumDic.Add(it, 0);
        if (_typeNumDic.ContainsKey(it)) _typeNumDic[it]++;
        else
        {
            _typeNumDic.Add(it, 1);
            _iptKeyLs.Add(it);//a new type
        }
    }

    private void RotImg(Image img, IptType it)
    {
        switch (it)
        {
            case IptType.South:
                img.gameObject.GetComponent<RectTransform>().rotation = Quaternion.AngleAxis(-90, Vector3.forward);
                return;
            case IptType.West:
                img.gameObject.GetComponent<RectTransform>().rotation = Quaternion.AngleAxis(180, Vector3.forward);
                return;
            case IptType.North:
                img.gameObject.GetComponent<RectTransform>().rotation = Quaternion.AngleAxis(90, Vector3.forward);
                return;
            case IptType.East:
                img.gameObject.GetComponent<RectTransform>().rotation = Quaternion.AngleAxis(0, Vector3.forward);
                return;
            default://east, angle depends on sprite asset
                return;
        }
    }

    /// <summary>
    /// Display num and word.
    /// </summary>
    /// <param name="idx">Word img idx.</param>
    /// <param name="tgtType">Which ipt of type to display.</param>
    private void DsplFullFormat(int idx, IptType tgtType)
    {
        DisplayNum(idx - 1, tgtType);
        DsplWord(idx, tgtType);
    }

    private void DisplayNum(int idx, IptType tgtType)
    {
        _wordImgs[idx].gameObject.SetActive(true);
        _wordImgs[idx].sprite = _wordNums[_typeNumDic[tgtType]];
        _wordImgs[idx].gameObject.GetComponent<RectTransform>().rotation = Quaternion.AngleAxis(0, Vector3.forward);//rotate
    }

    private void DsplWord(int idx, IptType tgtType)
    {
        _wordImgs[idx].gameObject.SetActive(true);
        _wordImgs[idx].sprite = _pNumDic[tgtType] < _typeNumDic[tgtType] - _pNumDic[tgtType] ?
            _words[_pNumDic[tgtType]] : _pWords[_typeNumDic[tgtType] - _pNumDic[tgtType]];
        RotImg(_wordImgs[idx], tgtType);
    }
}
